//#include "h1010.h"
#include "LED.h"
#include "SOSZ.h"
#include "I2C_IO_Driver.h"
#include "main.h"
#include "test.h"
#include "GA.h"

#include <string.h>

#define TERM1_OP 1
#define TERM2_OP 2
#define TERM3_OP 4
#define TERM4_OP 8
#define TERM34_OP 16
#define TERM23_OP 32
#define TERM12_OP 64
#define TERM1 1
#define TERM2 2
#define TERM3 3
#define TERM4 4
#define TERM_OP_MASK_1 (TERM2_OP|TERM12_OP)

//enum H1_state h1State = INHIBITED;
//enum Enabled_state enabledState = IDLE;
//enum Active_state activeState = TURN_ON_DELAY;

struct SO_state {
	BYTE nullX[4];
	BYTE nullXY[3];
	BYTE null;
	BYTE sumX[4];
	BYTE sumXY[3];
	BYTE termXmet[4];
	BYTE termXY[3];
	BYTE init:1;
	BYTE trigger:1;
	BYTE triggerTimerLatched:1;
	BYTE onEntry:1;
	BYTE onExit:1;
	BYTE isLockedTurnOffDelay:1;
	BYTE unused:2;
	enum SO_mode mode;
	enum H1_state h1State;
	enum Enabled_state enabledState;
	enum Active_state activeState;
	enum objectStatus abortStatus;
};
struct SO_driver{
	struct SO_state SOstate;
	struct SO * pSOconfig;
	unsigned int remainingPeriod;
	unsigned int timer;
	unsigned int abortTimer;
	unsigned int timerDelayOff;
	unsigned int TurnOnDelay;
};
struct SO_driver szDriver[TOTAL_SZ] = {0};
struct SO_driver soDriver[TOTAL_SO] = {0};
struct SO_driver rlDriver[MAX_REL] = {0};

struct SO_outputPhyDriver{
	struct SO_driver * pSosz;
	enum LED_INDEX alarmLed;
	enum LED_INDEX faultLed;
	enum SO_LED soLedBit;
	enum OSO_I2C osoBit;
	GPIO_pin_t outputPin;
	unsigned char serviceMode;
};
struct SO_outputPhyDriver soPhyDriver[TOTAL_SO] = {0};
struct SO_outputPhyDriver rlPhyDriver[MAX_REL] = {0};
struct xAbort * pXabort;// = (struct xAbort *)&pConfigMemRAM->xabort;

BYTE SO_normalState = 0;
BYTE SO_mask = 0;
BYTE REL_lo_mask= 0;
/*BYTE SO_maskFWS = 0;
BYTE REL_lo_maskFWS= 0;*/

BYTE sz4to1_si12to9_maskByte= 0;
BYTE sz12to5_maskByte = 0;
BYTE si8to1_maskByte= 0;
BYTE SIWar_maskByte= 0;
BYTE SZHi_maskByte= 0;
BYTE SZ12to5_maskByte= 0;
BYTE tmp = 1;

WORD SI_maskWord = 0;
WORD SZ_maskWord = 0;

void SOSZ_notifySOSZ_SIwarAlm(BYTE index);
void SOSZ_notifySOSZ_SZtrigger(WORD index);
void SOSZ_notifySOSZ_SIHiAlm(BYTE index);
//void SOSZ_notifySOSZ_SILoAlm(BYTE index);
void SOSZ_notifySOSZ_SOtrigger(BYTE trigger);
void SOSZ_notifySOSZ_RELtrigger(BYTE index);
void SOSZ_clearSOSZ_SIwarAlm(BYTE index);
void SOSZ_clearSOSZ_SZtrigger(WORD index);
void SOSZ_clearSOSZ_SIHiAlm(BYTE index);
//void SOSZ_clearSOSZ_SILoAlm(BYTE index);
void SOSZ_clearSOSZ_SOtrigger(BYTE trigger);
void SOSZ_clearSOSZ_RELtrigger(BYTE index);
void SOSZ_clearAllMasks(void);
//void SOSZ_notifySOSZ_SZtrigger(BYTE trigger);
//void SOSZ_clearSOSZ_SZtrigger(BYTE trigger);
void SOSZ_updateConfig(BYTE * buff);
//void SOSZ_thread(enum e_mode _mode);
void SOSZ_stateMachineTick(struct SO_driver * pSOd);
void SOSZ_activeSM_checkTimerByState(struct SO_driver * pSOd);
void SOSZ_stateTransCheckForAbort(struct SO_driver * pSOd, enum Active_state abortActive, enum Active_state abortNotActive);
enum objectStatus SOSZ_getAbortStatus(struct SO_driver * pSOd);
int SOSZ_activeSM_turnOnDelaySuper_during(struct SO_driver * pSOd);

//void SO_initStates(void);

void SO_state_initStates(struct SO_state * p)
{
	p->h1State = INHIBITED;
	p->enabledState = IDLE;
	p->activeState = IDLE_ACTIVE;//TURN_ON_DELAY;
}
BYTE SO_state_compare(struct SO_state * soh1, struct SO_state * soh2)
{
	unsigned int len = sizeof(struct SO_state);
	unsigned int i;
	BYTE * p1 = (BYTE*)soh1;
	BYTE * p2 = (BYTE*)soh2;
	BYTE rtn = 0;
	for (i=0; i<len; i++)
	{
		if (*p1 != *p2)
		{
			__no_operation();
			rtn++;
		}
		p1++; p2++;
	}
	return rtn;
}
BYTE voidCompare(BYTE * obj1, BYTE * obj2, unsigned int objSizeBytes)
{
	unsigned int i;
	BYTE * p1 = (BYTE*)obj1;
	BYTE * p2 = (BYTE*)obj2;
	BYTE rtn = 0;
	for (i=0; i<objSizeBytes; i++)
	{
		if (*p1 != *p2)
		{
			__no_operation();
			rtn++;
		}
		p1++; p2++;
	}
	return rtn;
}
void SOSZ_resetSOSZconfig(struct SO * p, unsigned int numStructs)
{
	unsigned int i;
	for (i=0; i<numStructs; i++)
	{
		memset((BYTE *)p, 0, sizeof(struct SO));
		p++;
	}
}
void SOSZ_resetSOSZdriver(struct SO_driver * p, unsigned int numStructs)
{
	unsigned int i;
	for (i=0; i<numStructs; i++)
	{
		memset((BYTE *)p, 0, sizeof(struct SO_driver));
		p++;
	}
}
void SO_driver_mapToCfgMem(void)
{
	int i;
	for(i=0;i<TOTAL_SO;i++) {
//		soDriver[i].pSOconfig = &configMemRAM.so[i];
		soDriver[i].pSOconfig = (struct SO *)&pConfigMemRAM->so[i];
	}
	for(i=0;i<TOTAL_SZ;i++) {
//		soDriver[i].pSOconfig = &configMemRAM.so[i];
		szDriver[i].pSOconfig = (struct SO *)&pConfigMemRAM->sz[i];
	}
	for(i=0;i<MAX_REL;i++) {
//		soDriver[i].pSOconfig = &configMemRAM.so[i];
		rlDriver[i].pSOconfig = (struct SO *)&pConfigMemRAM->rl[i];
	}
	pXabort = (struct xAbort *)&pConfigMemRAM->xabort;
}

void SOSZ_init(void)
{
	SOSZ_clearAllMasks();
	int sizeSO = sizeof(struct SO_driver);
	int sizeDR = sizeof(struct SO_outputPhyDriver);
//	memset((BYTE*)pSOstate, 0, sizeof(struct SO_state));
	void * p;
	p = (void *)&soDriver[0];
	memset((BYTE*)p, 0, TOTAL_SO*sizeSO);
	p  = (void *)&szDriver[0];
	memset((BYTE*)p, 0, MAX_SZ*sizeSO);
	p  = (void *)&rlDriver[0];
	memset((BYTE*)p, 0, MAX_REL*sizeSO);

/*
	p  = (void *)&SO_faultDriver[0];
	memset((BYTE*)p, 0, TOTAL_SO*sizeof(struct SO_faultDriver_t));
*/

	p  = (void *)&soPhyDriver[0];
	memset((BYTE*)p, 0, TOTAL_SO*sizeDR);

	p  = (void *)&rlPhyDriver[0];
	memset((BYTE*)p, 0, MAX_REL*sizeDR);

//	SOSZ_resetSOSZconfig(soDriver[0].pSOconfig, 1);//TOTAL_SO);
	SO_driver_mapToCfgMem();
	int i;
	for (i=0; i<TOTAL_SO; i++)
	{
		memset((BYTE*)&soPhyDriver[i], 0, sizeDR);
		soPhyDriver[i].pSosz = &soDriver[i];
//		soPhyDriver[i].alarmLed = LED_SO_1_Alm;
		soPhyDriver[i].alarmLed += (enum LED_INDEX)i + LED_SO_1_Alm;
//		soPhyDriver[i].faultLed = LED_SO_1_Flt;
		soPhyDriver[i].faultLed += (enum LED_INDEX)i + LED_SO_1_Flt;
//		soPhyDriver[i].pSOfaultDriver = &SO_faultDriver[i];
		soPhyDriver[i].serviceMode = 0;
//		soPhyDriver[i].soLedBit = 0;
//		soPhyDriver[i].osoBit = 0;
	}
	for (i=0; i<MAX_REL; i++)
	{
		memset((BYTE*)&rlPhyDriver[i], 0, sizeof(struct SO_outputPhyDriver));
		rlPhyDriver[i].pSosz = &rlDriver[i];
//		rlPhyDriver[i].alarmLed = LED_SO_5_Alm;
		rlPhyDriver[i].alarmLed += (enum LED_INDEX)i + LED_SO_5_Alm;
//		rlPhyDriver[i].faultLed = LED_SO_5_Flt;
		rlPhyDriver[i].faultLed += (enum LED_INDEX)i + LED_SO_5_Flt;
//		rlPhyDriver[i].pSOfaultDriver = &SO_faultDriver[i];
		rlPhyDriver[i].serviceMode = 0;
	}
	SOSZ_updateSOSZ_SOnormalState();
//	soPhyDriver[1].sosz = &soDriver[1];
//	soPhyDriver[1].alarmLed = LED_SO_2_Alm;
//	soPhyDriver[1].faultLed = LED_SO_2_Flt;
}
// Map -- SZ 1 to 12, 	SO 1 to 4, 		REL 1 to 20
//           1 to 12    13 to 16     	17 to 36
//        MAX_SZ  12  	MAX_SO 4   		MAX_REL 4
//        TOTAL_SZ  12  TOTAL_SO 4   	TOTAL_REL 16
void SOSZ_updateConfigHelper(struct SO * sPtr, BYTE * buff, unsigned int size)
{
	struct SO * pSO;
	BYTE * p = buff;
	unsigned int bytes = sizeof(struct SO)*size;
	BYTE i;
	for(i=0; i<size; i++)
	{
		pSO = sPtr++;
		p = (BYTE *)pSO;
		memcpy(p, buff, bytes);
	}
}
void SOSZ_updateConfig(BYTE * buff)
{
	BYTE * p = buff;
	SOSZ_updateConfigHelper(szDriver[0].pSOconfig,  p, TOTAL_SZ);
	SOSZ_updateConfigHelper(soDriver[0].pSOconfig, p, TOTAL_SO);
	SOSZ_updateConfigHelper(rlDriver[0].pSOconfig, p, MAX_REL);
}
/*void SOSZ_refreshConfig(BYTE index)
{
	struct SO * pSO;
	struct SO * pSOactive;
	pSO = &SO_config[index];
	pSOactive = &SO_configActive[index];
	unsigned int size = sizeof(struct SO); // pSO_config->End - pSO_config->Start;
	while (size--)
	{
		*pSOactive++ = *pSO++;
	}
}*/
void SO_driver_termXhelperInit(const struct SO_driver * _pSOd, BYTE numObjects)
{
	BYTE termNum;
	BYTE * warTrigg;// = &pSO->term[0].SIWarTriggers;
	struct SO_driver * pSOd = (struct SO_driver *) _pSOd;
	while (numObjects--)
	{
		for (termNum = 0; termNum <4; termNum++)
		{
			warTrigg = &pSOd->pSOconfig->term[termNum].SIWarTriggers;
			if (*(warTrigg + 0)) pSOd->SOstate.sumX[termNum]+=1;
			if (*(warTrigg + 1)) pSOd->SOstate.sumX[termNum]+=2;
			if (*(warTrigg + 2)) pSOd->SOstate.sumX[termNum]+=4;
			if (*(warTrigg + 3)) pSOd->SOstate.sumX[termNum]+=8;
		}
		pSOd++;
	}
}
void SO_driver_opXY_helperInit(const struct SO_driver * _pSOd, BYTE numObjects)
{
	BYTE termNum;
	BYTE * warTrigg1;
	BYTE * warTrigg2;
	struct SO_driver * pSOd = (struct SO_driver *) _pSOd;
	while (numObjects--)
	{
		for (termNum = 0; termNum <3; termNum++)
		{
			warTrigg1 = &pSOd->pSOconfig->term[termNum].SIWarTriggers;
			warTrigg2 = &pSOd->pSOconfig->term[termNum+1].SIWarTriggers;
			if (*(warTrigg1 + 0) || *(warTrigg1 + 1) || *(warTrigg1 + 2) || *(warTrigg1 + 3)) pSOd->SOstate.sumXY[termNum] += 1;
			if (*(warTrigg2 + 0) || *(warTrigg2 + 1) || *(warTrigg2 + 2) || *(warTrigg2 + 3)) pSOd->SOstate.sumXY[termNum] += 2;
		}
		pSOd++;
	}
}
void SO_driver_termXhelper(const struct SO_driver * _pSOd, BYTE numObjects)//(struct SO * SOp)
{
	BYTE * warTrigg;
	BYTE termNum;
	BYTE * termOp;
	struct SO_driver * pSOd = (struct SO_driver *) _pSOd;
	struct SO_state * pState;
	BYTE triggerMet[4];
	while (numObjects--)
	{
		termOp = (BYTE *)pSOd->pSOconfig;
		termOp += 2;
//		warTrigg = pSOd->SpSOconfig>term[0].SIWarTriggers;
		pState = (struct SO_state *)&pSOd->SOstate;
		for (termNum = 0; termNum <4; termNum++)
		{
			warTrigg = &pSOd->pSOconfig->term[termNum].SIWarTriggers;
			triggerMet[0] = ((*(warTrigg + 0)  & SIWar_maskByte) 			== (*(warTrigg + 0))) ?  1 :  0;
			triggerMet[1] = ((*(warTrigg + 1)  & SZ12to5_maskByte) 			== (*(warTrigg + 1))) ?  1 :  0;
			triggerMet[2] = ((*(warTrigg + 2)  & sz4to1_si12to9_maskByte)	== (*(warTrigg + 2))) ?  1 :  0;
			triggerMet[3] = ((*(warTrigg + 3)  & si8to1_maskByte) 			== (*(warTrigg + 3))) ?  1 :  0;

			if (*termOp & (1<<(termNum+0))) // if OR
			{
				if ((*(warTrigg + 0)  & SIWar_maskByte) || (*(warTrigg + 1) & SZ12to5_maskByte) || (*(warTrigg + 2) & sz4to1_si12to9_maskByte) || (*(warTrigg + 3) & si8to1_maskByte))
					pState->termXmet[termNum] = 1;
				else
					pState->termXmet[termNum] = 0;
			}
			else							// else AND
			{
				switch (pSOd->SOstate.sumX[termNum])
				{
//					#define LONG_DUMMY_FILLER_MORE_FILLER 1

					case(0):
							pState->termXmet[termNum] = 0;
							pSOd->SOstate.nullX[termNum] = 1;
							break;
					case(1):
							pState->termXmet[termNum] = (triggerMet[0]) ? 	1	: 	0;
							break;
					case(2):
							pState->termXmet[termNum] = (triggerMet[1]) ? 	1	: 	0;
							break;
					case(3):
							pState->termXmet[termNum] = (triggerMet[0]&&triggerMet[1]) ? 	1	: 	0;
							break;
//							if ((*(warTrigg + 0) & SIWar_maskByte) && (*(warTrigg + 1) & SZ12to5_maskByte))
//							{pState->termXmet[termNum] = 1;} else {pState->termXmet[termNum] = 0;} break;
					case(4):
							pState->termXmet[termNum] = (triggerMet[2]) ? 	1	: 	0;
							break;
					case(5):
							pState->termXmet[termNum] = (triggerMet[0]&&triggerMet[2]) ? 	1	: 	0;
							break;
//							if ((*(warTrigg + 0) & SIWar_maskByte) && (*(warTrigg + 2) & sz4to1_si12to9_maskByte))
//								{pState->termXmet[termNum] = 1;} else {pState->termXmet[termNum] = 0;} break;
					case(6):
							pState->termXmet[termNum] = (triggerMet[1]&&triggerMet[2]) ? 	1	: 	0;
							break;
//							if ((*(warTrigg + 1) & SZ12to5_maskByte)   && (*(warTrigg + 2) & sz4to1_si12to9_maskByte)								 )
//								{pState->termXmet[termNum] = 1;} else {pState->termXmet[termNum] = 0;} break;
					case(7):
							pState->termXmet[termNum] = (triggerMet[0]&&triggerMet[1]&&triggerMet[2]) ? 	1	: 	0;
							break;
//							if ((*(warTrigg + 0) & SIWar_maskByte) && (*(warTrigg + 1) & SZ12to5_maskByte)   && (*(warTrigg + 2) & sz4to1_si12to9_maskByte)								 )
//								{pState->termXmet[termNum] = 1;} else {pState->termXmet[termNum] = 0;} break;
					case(8):
							pState->termXmet[termNum] = (triggerMet[3]) ? 	1	: 	0;
							break;
					case(9):
							pState->termXmet[termNum] = (triggerMet[0]&&triggerMet[3]) ? 	1	: 	0;
							break;
//							if ((*(warTrigg + 0) & SIWar_maskByte)&& (*(warTrigg + 3) & si8to1_maskByte))
//								{pState->termXmet[termNum] = 1;} else {pState->termXmet[termNum] = 0;} break;
					case(10):
							pState->termXmet[termNum] = (triggerMet[1]&&triggerMet[3]) ? 	1	: 	0;
							break;
//							if ((*(warTrigg + 1) & SZ12to5_maskByte)&& (*(warTrigg + 3) & si8to1_maskByte))
//								{pState->termXmet[termNum] = 1;} else {pState->termXmet[termNum] = 0;} break;
					case(11):
							pState->termXmet[termNum] = (triggerMet[0]&&triggerMet[1]&&triggerMet[3]) ? 	1	: 	0;
							break;
//							if ((*(warTrigg + 0) & SIWar_maskByte) && (*(warTrigg + 1) & SZ12to5_maskByte) && (*(warTrigg + 3) & si8to1_maskByte))
//								{pState->termXmet[termNum] = 1;} else {pState->termXmet[termNum] = 0;} break;
					case(12):
							pState->termXmet[termNum] = (triggerMet[2]&&triggerMet[3]) ? 	1	: 	0;
							break;
//							if ((*(warTrigg + 2) & sz4to1_si12to9_maskByte) && (*(warTrigg + 3) & si8to1_maskByte))
//								{pState->termXmet[termNum] = 1;} else {pState->termXmet[termNum] = 0;} break;
					case(13):
							pState->termXmet[termNum] = (triggerMet[0]&&triggerMet[1]&&triggerMet[3]) ? 	1	: 	0;
							break;
//							if ((*(warTrigg + 0) & SIWar_maskByte) && (*(warTrigg + 2) & sz4to1_si12to9_maskByte) && (*(warTrigg + 3) & si8to1_maskByte))
//								{pState->termXmet[termNum] = 1;} else {pState->termXmet[termNum] = 0;} break;
					case(14):
							pState->termXmet[termNum] = (triggerMet[1]&&triggerMet[2]&&triggerMet[3]) ? 	1	: 	0;
							break;
//							if ((*(warTrigg + 1) & SZ12to5_maskByte)   && (*(warTrigg + 2) & sz4to1_si12to9_maskByte) && (*(warTrigg + 3) & si8to1_maskByte))
//								{pState->termXmet[termNum] = 1;} else {pState->termXmet[termNum] = 0;} break;
					case(15):
							pState->termXmet[termNum] = (triggerMet[0]&&triggerMet[1]&&triggerMet[2]&&triggerMet[3]) ? 	1	: 	0;
							break;
//							if ((*(warTrigg + 0) & SIWar_maskByte) && (*(warTrigg + 1) & SZ12to5_maskByte)   && (*(warTrigg + 2) & sz4to1_si12to9_maskByte) && (*(warTrigg + 3) & si8to1_maskByte))
//								{pState->termXmet[termNum] = 1;} else {pState->termXmet[termNum] = 0;} break;
					default:
							pState->termXmet[termNum] = 0;
							pSOd->SOstate.nullX[termNum] = 1;
							break;
				}
			}
///			if(pSOd->pSOconfig.)
		}
		pSOd++;
	}
}
BYTE SOSZ_termXhelper(BYTE * warTrigg, BYTE op, BYTE * null, BYTE * sum)//(struct SO * SOp)
{
	BYTE termMet = 0;
	*sum = 0;
	*null = 0;
	if (op)
	{
		if ((*(warTrigg + 0)  & SIWar_maskByte) || (*(warTrigg + 1) & SZ12to5_maskByte) || (*(warTrigg + 2) & sz4to1_si12to9_maskByte) || (*(warTrigg + 3) & si8to1_maskByte))
				termMet = 1;
	}
	else
	{
		if (*(warTrigg + 0)) *sum+=1;
		if (*(warTrigg + 1)) *sum+=2;
		if (*(warTrigg + 2)) *sum+=4;
		if (*(warTrigg + 3)) *sum+=8;
		switch (*sum)
		{
			#define LONG_DUMMY_FILLER_MORE_FILLER 1

			case(0): termMet = 0; *null = 1; break;
			case(1):  if ((*(warTrigg + 0) & SIWar_maskByte) && LONG_DUMMY_FILLER_MORE_FILLER && LONG_DUMMY_FILLER_MORE_FILLER && LONG_DUMMY_FILLER_MORE_FILLER) termMet = 1; break;
			case(2):  if (LONG_DUMMY_FILLER_MORE_FILLER  && (*(warTrigg + 1) & SZ12to5_maskByte)   && LONG_DUMMY_FILLER_MORE_FILLER && LONG_DUMMY_FILLER_MORE_FILLER) termMet = 1; break;
			case(3):  if ((*(warTrigg + 0) & SIWar_maskByte) && (*(warTrigg + 1) & SZ12to5_maskByte)   && LONG_DUMMY_FILLER_MORE_FILLER && LONG_DUMMY_FILLER_MORE_FILLER) termMet = 1; break;
			case(4):  if (LONG_DUMMY_FILLER_MORE_FILLER  && LONG_DUMMY_FILLER_MORE_FILLER && (*(warTrigg + 2) & sz4to1_si12to9_maskByte) && LONG_DUMMY_FILLER_MORE_FILLER) termMet = 1; break;
			case(5):  if ((*(warTrigg + 0) & SIWar_maskByte) && LONG_DUMMY_FILLER_MORE_FILLER && (*(warTrigg + 2) & sz4to1_si12to9_maskByte) && LONG_DUMMY_FILLER_MORE_FILLER) termMet = 1; break;
			case(6):  if (LONG_DUMMY_FILLER_MORE_FILLER  && (*(warTrigg + 1) & SZ12to5_maskByte)   && (*(warTrigg + 2) & sz4to1_si12to9_maskByte) && LONG_DUMMY_FILLER_MORE_FILLER) termMet = 1; break;
			case(7):  if ((*(warTrigg + 0) & SIWar_maskByte) && (*(warTrigg + 1) & SZ12to5_maskByte)   && (*(warTrigg + 2) & sz4to1_si12to9_maskByte) && LONG_DUMMY_FILLER_MORE_FILLER) termMet = 1; break;
			case(8):  if (LONG_DUMMY_FILLER_MORE_FILLER  && LONG_DUMMY_FILLER_MORE_FILLER && LONG_DUMMY_FILLER_MORE_FILLER && (*(warTrigg + 3) & si8to1_maskByte)) termMet = 1; break;
			case(9):  if ((*(warTrigg + 0) & SIWar_maskByte) && LONG_DUMMY_FILLER_MORE_FILLER && LONG_DUMMY_FILLER_MORE_FILLER && (*(warTrigg + 3) & si8to1_maskByte)) termMet = 1; break;
			case(10): if (LONG_DUMMY_FILLER_MORE_FILLER  && (*(warTrigg + 1) & SZ12to5_maskByte)   && LONG_DUMMY_FILLER_MORE_FILLER && (*(warTrigg + 3) & si8to1_maskByte)) termMet = 1; break;
			case(11): if ((*(warTrigg + 0) & SIWar_maskByte) && (*(warTrigg + 1) & SZ12to5_maskByte)   && LONG_DUMMY_FILLER_MORE_FILLER && (*(warTrigg + 3) & si8to1_maskByte)) termMet = 1; break;
			case(12): if (LONG_DUMMY_FILLER_MORE_FILLER  && LONG_DUMMY_FILLER_MORE_FILLER && (*(warTrigg + 2) & sz4to1_si12to9_maskByte) && (*(warTrigg + 3) & si8to1_maskByte)) termMet = 1; break;
			case(13): if ((*(warTrigg + 0) & SIWar_maskByte) && LONG_DUMMY_FILLER_MORE_FILLER && (*(warTrigg + 2) & sz4to1_si12to9_maskByte) && (*(warTrigg + 3) & si8to1_maskByte)) termMet = 1; break;
			case(14): if (LONG_DUMMY_FILLER_MORE_FILLER  && (*(warTrigg + 1) & SZ12to5_maskByte)   && (*(warTrigg + 2) & sz4to1_si12to9_maskByte) && (*(warTrigg + 3) & si8to1_maskByte)) termMet = 1; break;
			case(15): if ((*(warTrigg + 0) & SIWar_maskByte) && (*(warTrigg + 1) & SZ12to5_maskByte)   && (*(warTrigg + 2) & sz4to1_si12to9_maskByte) && (*(warTrigg + 3) & si8to1_maskByte)) termMet = 1; break;
			default: termMet = 0; *null = 1; break;
		}
	}
	return termMet;
}
void SO_driver_opXY_helper(const struct SO_driver * _pSOd, BYTE numObjects)//(struct SO * SOp)
{
	BYTE termNum;
	BYTE termX, termY;
	BYTE * termXYop;
	BYTE *termXY;
	struct SO_driver * pSOd = (struct SO_driver *) _pSOd;
	while (numObjects--)
	{
		for (termNum = 0; termNum <3; termNum++)
		{
			termX = pSOd->SOstate.termXmet[termNum+0];
			termY = pSOd->SOstate.termXmet[termNum+1];
			termXYop = (BYTE *)pSOd->pSOconfig; termXYop += 2;
			termXY = &pSOd->SOstate.termXY[termNum];
			switch(pSOd->SOstate.sumXY[termNum])
			{
				case(0): pSOd->SOstate.nullXY[termNum] = 1;	*termXY = 0;  break;
				case(1):
					if (termX)
					{
						*termXY = 1; __no_operation();
					}
					else
					{
						*termXY = 0; __no_operation();
					}
//					*termXY = 1;
					break;
				case(2):
					if (termY) { *termXY = 1; } else { *termXY = 0;}
					*termXY = 1;
					break;
				case(3):
					if (*termXYop & (1<<(6-termNum)))
					{
						if (termX || termY)
						{
							*termXY = 1;
						} else
						{
							*termXY = 0;
						}
					}
					else
					{
						if (termX && termY) { *termXY = 1; } else { *termXY = 0;}
					}
					break;
				default: pSOd->SOstate.nullXY[termNum] = 1;	*termXY = 1; break;
			}
		}
		pSOd++;
	}
}
void SOSZ_opXY_helper(BYTE * trig1, BYTE * trig2, BYTE xyOp, BYTE termX, BYTE termY, BYTE * null, BYTE * termXY, BYTE * sum)
{
	*sum = 0;
	*null = 0;
	*termXY = 0;
	if (*(trig1 + 0) || *(trig1 + 1) || *(trig1 + 2) || *(trig1 + 3)) *sum += 1;
	if (*(trig2 + 0) || *(trig2 + 1) || *(trig2 + 2) || *(trig2 + 3)) *sum += 2;
	switch (*sum)
	{
		case(0): *null = 1;	break;
		case(1): if (termX) *termXY = 1; break;
		case(2): if (termY) *termXY = 1; break;
		case(3):
			if (xyOp)
			{
				if (termX || termY) *termXY = 1;
			}
			else
			{
				if (termX && termY) *termXY = 1;
			}
			break;
		default: break;
	}
}
void SOSZ_opXY_eval(struct SO * pSO, struct SO_state * pSOstate, BYTE term1, BYTE term2)
{
}
void SO_driver_timerUpdateLogicUpdateTerms(struct SO_driver * pSOd, BYTE numObjects)
{
	SO_driver_termXhelper(pSOd, numObjects);
	SO_driver_opXY_helper(pSOd, numObjects);
	struct SO_state * pSOstate = &pSOd->SOstate;
	pSOstate->null = pSOstate->nullXY[0] + pSOstate->nullXY[1]*2 + pSOstate->nullXY[2]*4;
}
void SOSZ_timerUpdateLogicUpdateTerms(struct SO * pSO, struct SO_state * pSOstate)
{
	memset((BYTE*)pSOstate, 0, sizeof(struct SO_state));
	pSOstate->termXmet[0] = SOSZ_termXhelper(&pSO->term[0].SIWarTriggers, pSO->Term1Op, &pSOstate->nullX[0], &pSOstate->sumX[0]);
	pSOstate->termXmet[1] = SOSZ_termXhelper(&pSO->term[1].SIWarTriggers, pSO->Term2Op, &pSOstate->nullX[1], &pSOstate->sumX[1]);
	pSOstate->termXmet[2] = SOSZ_termXhelper(&pSO->term[2].SIWarTriggers, pSO->Term3Op, &pSOstate->nullX[2], &pSOstate->sumX[2]);
	pSOstate->termXmet[3] = SOSZ_termXhelper(&pSO->term[3].SIWarTriggers, pSO->Term4Op, &pSOstate->nullX[3], &pSOstate->sumX[3]);
//	SO_driver_termXhelper(&soDriver[0], 4);

//		SOSZ_opXY_eval(pSO, pSOstate, TERM1);
	SOSZ_opXY_helper(&pSO->term[0].SIWarTriggers, &pSO->term[1].SIWarTriggers, pSO->Term12Op, pSOstate->termXmet[0], pSOstate->termXmet[1], &pSOstate->nullXY[0], &pSOstate->termXY[0], &pSOstate->sumXY[0]);
	SOSZ_opXY_helper(&pSO->term[1].SIWarTriggers, &pSO->term[2].SIWarTriggers, pSO->Term23Op, pSOstate->termXmet[1], pSOstate->termXmet[2], &pSOstate->nullXY[1], &pSOstate->termXY[1], &pSOstate->sumXY[1]);
	SOSZ_opXY_helper(&pSO->term[2].SIWarTriggers, &pSO->term[3].SIWarTriggers, pSO->Term34Op, pSOstate->termXmet[2], pSOstate->termXmet[3], &pSOstate->nullXY[2], &pSOstate->termXY[2], &pSOstate->sumXY[2]);
//	SO_driver_opXY_helper(&soDriver[0], 4);

	pSOstate->null = pSOstate->nullXY[0] + pSOstate->nullXY[1]*2 + pSOstate->nullXY[2]*4;
	pSOstate->init = 1;
}
void SO_driver_timerUpdateLogic(const struct SO_driver * _pSOd, BYTE numSOSZobjects)
{
	struct SO_driver * pSOd = (struct SO_driver *) _pSOd;
	struct SO_state * pSOstate = &pSOd->SOstate;
	if (pSOstate->init == 0)// pSOstate->init == 0)
	{
//		SOSZ_timerUpdateLogicInit(pSO, pSOstate);

		SO_driver_termXhelperInit(pSOd, numSOSZobjects);
		SO_driver_opXY_helperInit(pSOd, numSOSZobjects);
		pSOstate->init = 1;
//		SOSZ_termXhelperInit(&pSO->term[0].SIWarTriggers, pSO->Term1Op, &pSOstate->null1);
//		SOSZ_opXY_helperInit(&pSO->term[0].SIWarTriggers, &pSO->term[1].SIWarTriggers, pSO->Term12Op, pSOstate->term1met, pSOstate->term2met, &pSOstate->null12, &pSOstate->termXY[0]);
	}
	SO_driver_timerUpdateLogicUpdateTerms(pSOd, numSOSZobjects);
	switch (pSOstate->null)
	{
		case (0): pSOstate->trigger = pSOstate->termXY[0] && pSOstate->termXY[1] && pSOstate->termXY[2];  break;
		case (1): pSOstate->trigger = 0x0001 		 	&& pSOstate->termXY[1] && pSOstate->termXY[2];  break;
		case (2): pSOstate->trigger = pSOstate->termXY[0] && 0x0001 			  && pSOstate->termXY[2];  break;
		case (3): pSOstate->trigger = 0x0001 		 	&& 0x0001 			  && pSOstate->termXY[2];  break;
		case (4): pSOstate->trigger = pSOstate->termXY[0] && pSOstate->termXY[1] && 0x0001; 	    	break;
		case (5): pSOstate->trigger = 0x0001 		 	&& pSOstate->termXY[1] && 0x0001; 			break;
		case (6): pSOstate->trigger = pSOstate->termXY[0] && 0x0001 			  && 0x0001; 			break;
		case (7): pSOstate->trigger = 0; break;
	}
}
void SOSZ_timerUpdateLogic(struct SO * pSO, struct SO_state * pSOstate)
{
//	if (pSOstate->init == 0)
//	{
		SOSZ_timerUpdateLogicUpdateTerms(pSO, pSOstate);
//	}
	switch (pSOstate->null)
	{
		case (0): pSOstate->trigger = pSOstate->termXY[0] && pSOstate->termXY[1] && pSOstate->termXY[2]; break;
		case (1): pSOstate->trigger = 0x0001 		 	&& pSOstate->termXY[1] && pSOstate->termXY[2]; break;
		case (2): pSOstate->trigger = pSOstate->termXY[0] && 0x0001 			  && pSOstate->termXY[2]; break;
		case (3): pSOstate->trigger = 0x0001 		 	&& 0x0001 			  && pSOstate->termXY[2]; break;
		case (4): pSOstate->trigger = pSOstate->termXY[0] && pSOstate->termXY[1] && 0x0001; 			break;
		case (5): pSOstate->trigger = 0x0001 		 	&& pSOstate->termXY[1] && 0x0001; 			break;
		case (6): pSOstate->trigger = pSOstate->termXY[0] && 0x0001 			  && 0x0001; 			break;
		case (7): pSOstate->trigger = 0; break;
	}
}
void enabled_IDLE_SM(struct SO_driver * pSOd)
{
	__no_operation();
}
void enabled_FAULT_SM(struct SO_driver * pSOd)
{
	__no_operation();
}
void enabled_ACTIVE_SM(struct SO_driver * pSOd)
{
	struct SO_state   * pSOstate = &pSOd->SOstate;
	pSOstate->triggerTimerLatched = 0;
	if ((pSOd->pSOconfig->timers.TurnOffDelay)
			&&(pSOstate->activeState != TURN_ON_DELAY)
			&&(pSOstate->activeState != ABORT_TURN_ON_ACTIVE)
			&&(pSOstate->activeState != ABORT_TURN_ON_RELEASED))
	{
		pSOstate->triggerTimerLatched = 1;
		if (pSOd->timerDelayOff)
		{
			pSOd->timerDelayOff--;
			if (pSOd->timerDelayOff == 0)
			{
				pSOstate->activeState = TURN_OFF_DELAY;
				pSOstate->onEntry = 0;
				pSOstate->isLockedTurnOffDelay = 1;
			}
		}
	}
	switch (pSOstate->activeState)
	{
//		case IDLE: // does not fail...
//			break;
		case TURN_ON_DELAY:
			if (SOSZ_activeSM_turnOnDelaySuper_during(pSOd))
				__no_operation();
			else if (SOSZ_getAbortStatus(pSOd) == OBJ_S_ACTIVE)
			{
				SOSZ_stateTransCheckForAbort(pSOd, ABORT_TURN_ON_ACTIVE, TURN_ON_DELAY);
//				SOSZ_activeSM_checkTimerByState(pSOd);
			}
			break;
		case ABORT_TURN_ON_ACTIVE:
			if (SOSZ_activeSM_turnOnDelaySuper_during(pSOd))
				__no_operation();
			else if (SOSZ_getAbortStatus(pSOd) == OBJ_S_INACTIVE)
			{
				pSOstate->activeState = ABORT_TURN_ON_RELEASED;
			}
			break;
		case ABORT_TURN_ON_RELEASED:
			SOSZ_activeSM_turnOnDelaySuper_during(pSOd);
			break;
		case ABORT_WAIT_FOR_RELEASE:
			if (SOSZ_getAbortStatus(pSOd) == OBJ_S_INACTIVE)
			{
//				SOSZ_activeSM_postTurnOnDelay_enterActiveRelease(pSOd);
				SOSZ_activeSM_checkTimerByState(pSOd);
			}
			break;
		case PULSE_ON:
			pSOstate->triggerTimerLatched = 1;
			if ((pSOd->pSOconfig->timers.PulsePeriod != 0)&&(pSOd->remainingPeriod-- == 0))
			{
				pSOstate->activeState = STEADY_ON;
				break;
			}
			if (pSOd->timer++ >= ((pSOd->pSOconfig->timers.PulseOnTimer)>>1))//pSO->timers.PulseOnTimer)
			{
				pSOd->timer = 1;
				pSOstate->onEntry = 0;
				pSOstate->activeState = PULSE_OFF;
			}
			break;
		case PULSE_OFF:
			pSOstate->triggerTimerLatched = 1;
			if ((pSOd->pSOconfig->timers.PulsePeriod != 0)&&(pSOd->remainingPeriod-- == 0))
			{
				pSOstate->activeState = STEADY_ON;
				break;
			}
			if (pSOd->timer++ >= ((pSOd->pSOconfig->timers.PulseOffTimer)>>1))//pSO->timers.PulseOffTimer)
//			if(pTimer->PulseOffTimer == 0)
			{
				if (pSOstate->trigger == 0)
				{
					pSOstate->enabledState = IDLE;
					pSOstate->activeState = IDLE_ACTIVE;
					pSOstate->triggerTimerLatched = 0;
					pSOd->timer = 0;
					break;
				}
				pSOd->timer = 1;
				pSOstate->activeState = PULSE_ON;
				pSOstate->onEntry = 1;
				break;
			}
			break;
		case STEADY_ON:
			pSOstate->onEntry = 1;
			break;
		case TURN_OFF_DELAY:
			if (pSOstate->trigger == 0)
			{
				pSOstate->enabledState = IDLE;
				pSOstate->activeState = IDLE_ACTIVE;
				pSOstate->isLockedTurnOffDelay = 0;
				pSOstate->triggerTimerLatched = 0;
			}
			break;
	}
}
enum Enabled_state SOSZ_test_getEnabledState(enum SO_objectType type, BYTE index)
{
	enum Enabled_state rtn;
	switch (type)
	{
		case (SO_T_SO):
			rtn = soDriver[index].SOstate.enabledState;
			break;
		case (SO_T_SZ):
			rtn = szDriver[index].SOstate.enabledState;
			break;
		case (SO_T_RL):
			rtn = rlDriver[index].SOstate.enabledState;
			break;
	}
	return rtn;
}
enum Active_state SOSZ_test_getActiveState(enum SO_objectType type, BYTE index)
{
	enum Active_state rtn;
	switch (type)
	{
		case (SO_T_SO):
			rtn = soDriver[index].SOstate.activeState;
			break;
		case (SO_T_SZ):
			rtn = szDriver[index].SOstate.activeState;
			break;
		case (SO_T_RL):
			rtn = rlDriver[index].SOstate.activeState;
			break;
	}
	return rtn;

}
void SOSZ_activeSM_checkTimerByState(struct SO_driver * pSOd)
{
	struct SO_state   * pSOstate = &pSOd->SOstate;
	pSOd->remainingPeriod = pSOd->pSOconfig->timers.PulsePeriod*10;//pSO->timers.PulsePeriod;
	pSOd->timerDelayOff = pSOd->pSOconfig->timers.TurnOffDelay*10;//pSO->timers.TurnOffDelay*10;
	pSOd->timer = 0;
	switch (pSOstate->activeState)
	{
	case IDLE_ACTIVE:
		if (pSOd->pSOconfig->timers.TurnOnDelay)
		{
//			pSOstate->activeState = TURN_ON_DELAY;
			SOSZ_stateTransCheckForAbort(pSOd, ABORT_TURN_ON_ACTIVE, TURN_ON_DELAY);
			break;
		}
	case TURN_ON_DELAY:
	case ABORT_TURN_ON_ACTIVE:
	case ABORT_TURN_ON_RELEASED:
		if (pSOd->pSOconfig->timers.PulseOnTimer)
		{
			SOSZ_stateTransCheckForAbort(pSOd, ABORT_TURN_ON_ACTIVE, PULSE_ON);
	//		pSOstate->activeState = PULSE_ON;
			break;
		}
	case PULSE_ON:
	case PULSE_OFF:
	case TURN_OFF_DELAY:
	case STEADY_ON:
	case ABORT_WAIT_FOR_RELEASE:
//		pSOstate->activeState = STEADY_ON;
		SOSZ_stateTransCheckForAbort(pSOd, ABORT_WAIT_FOR_RELEASE, STEADY_ON);
		break;
	}
/*	if (pSOd->pSOconfig->timers.TurnOnDelay)
	{
		SOSZ_stateTransCheckForAbort(pSOd, ABORT_TURN_ON_ACTIVE, TURN_ON_DELAY);
	}
	else if (pSOd->pSOconfig->timers.PulseOnTimer)
	{
		SOSZ_stateTransCheckForAbort(pSOd, ABORT_WAIT_FOR_RELEASE, PULSE_ON);
//		pSOstate->activeState = PULSE_ON;
	}
	else
	{
		SOSZ_stateTransCheckForAbort(pSOd, ABORT_WAIT_FOR_RELEASE, STEADY_ON);
//		pSOstate->activeState = STEADY_ON;
	}*/
}
/*void SOSZ_activeSM_postTurnOnDelay_enterActiveRelease(struct SO_driver * pSOd)
{
	struct SO_state   * pSOstate = &pSOd->SOstate;
	pSOd->timer = 0;
	pSOstate->onEntry = 1;
	// turnOnOutput(pSOd);
	// enter_PULSE_ON();
//				if (pTimer->PulsePeriod)

	if (pSOd->pSOconfig->timers.PulseOnTimer)//(pSOd->remainingPeriod)
	{
//			pSOstate->activeState = PULSE_ON;
		SOSZ_stateTransCheckForAbort(pSOd, ABORT_WAIT_FOR_RELEASE, PULSE_ON);
	}
	else
	{
//			pSOstate->activeState = STEADY_ON;
		SOSZ_stateTransCheckForAbort(pSOd, ABORT_WAIT_FOR_RELEASE, STEADY_ON);
		pSOstate->triggerTimerLatched = 0;
	}
}*/
int SOSZ_activeSM_turnOnDelaySuper_during(struct SO_driver * pSOd)
{
	int trans = 0;
	struct SO_state   * pSOstate = &pSOd->SOstate;
	pSOstate->triggerTimerLatched = 1;
	if (pSOstate->trigger == 0)
	{
		trans = 1;
		pSOstate->triggerTimerLatched = 0;
		pSOd->timer = 0;
		return trans;
	}
//			if (pSOd->timer++ >= pSOd->pSOconfig->timers.TurnOnDelay)//pSO->timers.TurnOnDelay)
	if (pSOd->timer++ >= pSOd->TurnOnDelay)//pSOconfig->timers.TurnOnDelay)//pSO->timers.TurnOnDelay)
	{
		trans = 1;
//		SOSZ_activeSM_postTurnOnDelay_enterActiveRelease(pSOd);
		SOSZ_activeSM_checkTimerByState(pSOd);
	}
	return trans;
}
void SOSZ_stateTransCheckForAbort(struct SO_driver * pSOd, enum Active_state abortActive, enum Active_state abortNotActive)
{
	struct SO_state   * pSOstate = &pSOd->SOstate;
	enum Active_state oldState = pSOstate->activeState;
	if (SOSZ_getAbortStatus(pSOd) == OBJ_S_ACTIVE)
	{
		pSOstate->activeState = abortActive;
	}
	else
	{
		pSOstate->activeState = abortNotActive;
	}
	if (pSOstate->activeState == TURN_ON_DELAY)
		pSOd->TurnOnDelay = pSOd->pSOconfig->timers.TurnOnDelay;
	else if ((pSOstate->activeState == ABORT_TURN_ON_ACTIVE) && (oldState == IDLE_ACTIVE))
		pSOd->TurnOnDelay = pSOd->pSOconfig->timers.TurnOnDelay;
	else if ((pSOstate->activeState == ABORT_TURN_ON_ACTIVE) && (oldState == TURN_ON_DELAY))
		pSOd->TurnOnDelay = pSOd->pSOconfig->timers.TurnOnDelay + pXabort->AbortTimer;
}
enum objectStatus SOSZ_checkAbortStatus(struct SO_driver * pSOd)
{
	pSOd->SOstate.abortStatus = OBJ_S_INVALID;
	if (pSOd->pSOconfig->OutputControl == SO_configByte_OutputControl_andOrAbort)
	{
		pSOd->SOstate.abortStatus = OBJ_S_INACTIVE;
		BYTE abortInput = pSOd->pSOconfig->AbortInput;
		BYTE abortMask = 1<<abortInput; // 0=SI_1, ..., 7=SI_8
		BYTE abortStatus = abortMask&si8to1_maskByte;
		if (abortStatus)
		{
			pSOd->SOstate.abortStatus = OBJ_S_ACTIVE;
		}
	}
	return pSOd->SOstate.abortStatus;
}
enum objectStatus SOSZ_getAbortStatus(struct SO_driver * pSOd)
{
	return pSOd->SOstate.abortStatus;
}
void SOSZ_stateMachineTick(struct SO_driver * pSOd)
{
	struct SO_state   * pSOstate = &pSOd->SOstate;
	switch (pSOstate->enabledState)
	{
		case IDLE:
			if (pSOstate->isLockedTurnOffDelay == 1)
			{
				__no_operation();
				if (pSOstate->trigger == 0)  // requires trigger to go away before SO can be driven again
				{
					pSOstate->isLockedTurnOffDelay = 0;
				}
			}
			else if (pSOstate->trigger)
			{
				pSOstate->enabledState = ACTIVE;
				pSOstate->activeState = IDLE_ACTIVE;
				SOSZ_checkAbortStatus(pSOd);
				SOSZ_activeSM_checkTimerByState(pSOd);
				enabled_ACTIVE_SM(pSOd);
				break;
			}
			enabled_IDLE_SM(pSOd);
			break;
		case ACTIVE:
			SOSZ_checkAbortStatus(pSOd);
			if (pSOstate->trigger==0 && pSOstate->triggerTimerLatched==0)
			{
				pSOstate->enabledState = IDLE;
				SOSZ_activeSM_checkTimerByState(pSOd);
				break;
			}
			enabled_ACTIVE_SM(pSOd);
			break;
		case FAULT:
			enabled_FAULT_SM(pSOd);
			break;
	}
}
void SOSZ_processMasks(const struct SO_driver * _pSOd, BYTE numSOSZobjects, BYTE * mask)
{
	struct SO_driver * pSOd = (struct SO_driver *)_pSOd;
	BYTE i;
	if (*mask)
	{
		for (i=0; i<numSOSZobjects; i++)
		{
			if(*mask & 1<<i)
			{
				if (mask == &SO_mask)
					SOSZ_stateMachineTick(&pSOd[i]);
				else if (mask == &SZ12to5_maskByte)
					SOSZ_stateMachineTick(&pSOd[i]);
				else if (mask == &REL_lo_mask)
					SOSZ_stateMachineTick(&pSOd[i]);
			}
			pSOd++;
		}
	}
}
RTN_TYPE SO_FWS_clearOutput(enum SO_objectType type, enum SO_objectNumber objNum)
{

	struct SO_driver * pSOd;
	RTN_TYPE rtn = RTN_SUCCESS;
	if (type == SO_T_SO)
	{
		pSOd = &soDriver[objNum];
		if (pSOd->SOstate.mode == SO_MODE_FWS)
			SOSZ_clearSOSZ_SOtrigger(1<<objNum);
		else
			rtn = RTN_ERR_FWS_DOESNT_DRIVE_SO;
//		SOSZ_notifySOSZ_SOtriggerFWS(1<<objNum);
	}
	else if (type == SO_T_RL)
	{
		pSOd = &rlDriver[objNum];
		if (pSOd->SOstate.mode == SO_MODE_FWS)
			SOSZ_clearSOSZ_RELtrigger(1<<objNum);
		else
			rtn = RTN_ERR_FWS_DOESNT_DRIVE_SO;
//		SOSZ_notifySOSZ_RELtriggerFWS(1<<objNum);
	}
	else
	{
		rtn = RTN_ERR_CFG_INVALID;
	}
	return rtn;
}
RTN_TYPE SO_FWS_notifyOutput(enum SO_objectType type, enum SO_objectNumber objNum)
{
	struct SO_driver * pSOd;
	RTN_TYPE rtn = RTN_SUCCESS;
	if (type == SO_T_SO)
	{
		pSOd = &soDriver[objNum];
		if (pSOd->SOstate.mode == SO_MODE_FWS)
			SOSZ_notifySOSZ_SOtrigger(1<<objNum);
		else
			rtn = RTN_ERR_FWS_DOESNT_DRIVE_SO;
//		SOSZ_notifySOSZ_SOtriggerFWS(1<<objNum);
	}
	else if (type == SO_T_RL)
	{
		pSOd = &rlDriver[objNum];
		if (pSOd->SOstate.mode == SO_MODE_FWS)
			SOSZ_notifySOSZ_RELtrigger(1<<objNum);
		else
			rtn = RTN_ERR_FWS_DOESNT_DRIVE_SO;
//		SOSZ_notifySOSZ_RELtriggerFWS(1<<objNum);
	}
	else
	{
		rtn = RTN_ERR_CFG_INVALID;
	}
	return rtn;
}
void SO_enableSOSZlogicMask(unsigned char object, BYTE * mask)
{
	if (mask == &SO_mask)
		SOSZ_notifySOSZ_SOtrigger(1<<object);
	else if (mask == &SZ12to5_maskByte)
		SOSZ_notifySOSZ_SZtrigger(1<<object);
	else if (mask == &REL_lo_mask)
		SOSZ_notifySOSZ_RELtrigger(1<<object);
}
void SO_disableSOSZlogicMask(unsigned char object, BYTE * mask)
{
	if (mask == &SO_mask)
		SOSZ_clearSOSZ_SOtrigger(1<<object);
	else if (mask == &SZ12to5_maskByte)
		SOSZ_clearSOSZ_SZtrigger(1<<object);
	else if (mask == &REL_lo_mask)
		SOSZ_clearSOSZ_RELtrigger(1<<object);
}
void SO_driver_timerUpdateDrivers(const struct SO_driver * _pSOd, BYTE numSOSZobjects, BYTE * mask)
{
	unsigned int i;
	struct SO_driver * pSOd = (struct SO_driver *) _pSOd;
	for (i=0; i<numSOSZobjects; i++)
	{
		if (pSOd->SOstate.mode == SO_MODE_SO)
		{
			switch (pSOd->pSOconfig->OutputControl)
			{
				case SO_configByte_OutputControl_disabled:
				{
					pSOd->SOstate.enabledState = IDLE;
					SO_disableSOSZlogicMask(i, mask);
				}
				break;
				case SO_configByte_OutputControl_andOr:
				case SO_configByte_OutputControl_andOrAbort:
				{
					SO_driver_timerUpdateLogic(pSOd, 1);
					if ((pSOd->SOstate.trigger)||(pSOd->SOstate.triggerTimerLatched))  // if trigger is set for SOSZ object
					{
						SOSZ_stateMachineTick(pSOd);
						// find object type and update the mask
						if(((pSOd->SOstate.activeState == STEADY_ON)||(pSOd->SOstate.activeState == PULSE_ON))
								&&(pSOd->SOstate.isLockedTurnOffDelay == 0)&&(pSOd->SOstate.enabledState == ACTIVE))
						{
							SO_enableSOSZlogicMask(i, mask);
						}
						else
						{
							SO_disableSOSZlogicMask(i, mask);
						}
					}
					else
					{
						pSOd->SOstate.enabledState = IDLE;
						pSOd->SOstate.activeState = IDLE_ACTIVE;
						SO_disableSOSZlogicMask(i, mask);
					}
				}
				break;
				case SO_configByte_OutputControl_genAlarm:
				{
					if (GA_STATUS_ON == GA_statusForSOSZ())
					{
						pSOd->SOstate.enabledState = GA_ACTIVE;
						SO_enableSOSZlogicMask(i, mask);
					}
					else //if((pSOd->SOstate.activeState == TURN_OFF_DELAY)||(pSOd->SOstate.activeState == PULSE_OFF))
					{
						pSOd->SOstate.enabledState = IDLE;
						SO_disableSOSZlogicMask(i, mask);
					}
				}
				break;
			}
		}
		else // mode == SO_MODE_FWS
		{
		}
		pSOd++;
	}
}
enum SO_phyState SO_getPhyDriverState(enum SO_objectType type, enum SO_objectNumber objNum)
{
	enum SO_phyState status = SO_PHY_INVALID;
	struct SO_outputPhyDriver * pSOpd;
	switch (type)
	{
		case SO_T_SO:
			pSOpd = &soPhyDriver[objNum];
			break;
		case SO_T_RL:
			pSOpd = &rlPhyDriver[objNum];
			break;
		case SO_T_SZ:
		default:
			status = SO_PHY_INVALID;
			break;
	}
	if (pSOpd)
	{
		status = (enum SO_phyState)pSOpd->outputPin.pin;
	}
	return status;
}
void SO_driver_timerUpdatePhyDrivers(const struct SO_outputPhyDriver * _pSOpd, BYTE numSOSZobjects, BYTE * mask)
{
	unsigned int i;
	struct SO_outputPhyDriver * pSOpd = (struct SO_outputPhyDriver *) _pSOpd;
//	struct SO_driver * pSOd = (struct SO_driver *) pSOpd->sosz->pSOconfig;
	for (i=0; i<numSOSZobjects; i++)
	{
		if ((pSOpd->pSosz->pSOconfig->OutputControl != SO_configByte_OutputControl_disabled)/*&&(pSOpd->pSosz->SOstate.mode == SO_MODE_SO)*/)
		{
			if(*mask & (1<<i))
			{
				//			if (pSOd->SOstate.triggerTimerLatched)
				if (mask == &SO_mask)
				{
					pSOpd->outputPin.pin = 1;
					LED_setRate(pSOpd->alarmLed, RATE_ON);
				}
		//					SOSZ_notifySOSZ_SOtrigger(1<<i);
				else if (mask == &SZ12to5_maskByte)
				{
				}
		//					SOSZ_notifySOSZ_SZtrigger(1<<i);
				else if (mask == &REL_lo_mask)
				{
					pSOpd->outputPin.pin = 1;
					LED_setRate(pSOpd->alarmLed, RATE_ON);
				}
			}
			else
			{
				pSOpd->outputPin.pin = 0;
				LED_setRate(pSOpd->alarmLed, RATE_OFF);
			}
		}
//					SOSZ_notifySOSZ_RELtrigger(1<<i);
		pSOpd++;
	}
//		if((pSOd->SOstate.activeState == STEADY_ON)||(pSOd->SOstate.activeState == PULSE_ON))

//			if(pSOd->SOstate.onEntry)
//		pSOd++;
}

void SOSZ_timerUpdateConfigs(struct SO * pSO, BYTE numSOSZobjects, struct SO_state * pSOstate, BYTE * mask)
{
	unsigned int i;
	for (i=0; i<numSOSZobjects; i++)
	{
//		memset((BYTE*)pSOstate, 0, sizeof(struct SO_state));
		SOSZ_timerUpdateLogic(pSO, pSOstate);
		if (pSOstate->trigger)  // if trigger is set for SOSZ object
		{
			// find object type and update the mask
			if (mask == &SO_mask)
				SOSZ_notifySOSZ_SOtrigger(1<<i);
			else if (mask == &SZ12to5_maskByte)
				SOSZ_notifySOSZ_SZtrigger(1<<i);
			else if (mask == &REL_lo_mask)
				SOSZ_notifySOSZ_RELtrigger(1<<i);
		}
	}
}
unsigned char so_msg[10];
//char * pMsg = &so_msg[0];
void SOSZ_serialDebugThread(void)
{
#if DEBUG_SERIAL_SO
	{
		so_msg[0] = (soDriver[0].timerDelayOff)>>8;
		so_msg[0] &= 0x0F;
		so_msg[1] = (soDriver[0].timerDelayOff)&0xFF;
		so_msg[2] = (unsigned char)soDriver[0].SOstate.activeState;//(SI_threadInfo[i].adcCount)&0xFF;

		so_msg[3] = (unsigned char)soDriver[0].SOstate.enabledState;//SI_threadInfo[i].adcState;
		so_msg[4] = (unsigned char)soDriver[0].SOstate.isLockedTurnOffDelay;//SI_threadInfo[i].alarmState;
		so_msg[5] = (unsigned char)soDriver[0].SOstate.trigger;//SI_threadInfo[i].alarmLed;
	//			extern unsigned char ticksADC;
		so_msg[6] = (unsigned char)soDriver[0].SOstate.triggerTimerLatched;//ticks;
		so_msg[7] = (unsigned char)soDriver[0].pSOconfig->timers.TurnOffDelay;
//		so_msg[8] = (unsigned char)_mode;
		so_msg[8] = (unsigned char)(soDriver[0].timer)>>8;
		so_msg[8] = (unsigned char)(soDriver[0].timer)&0xFF;
		so_msg[9] = (unsigned char)LED_getRate(soPhyDriver[0].alarmLed);

		if (_mode != MODE_NORMAL)
		{
			__no_operation();
		}

	//			msg[2] = null[0];
	//			msg[3] = null[0];
		//	*(pMsg+6) = "\n";
//		enum DebugCmd cmd = DebugCmd_SO_1;
//		cmd += (enum DebugCmd)i;
		Test_Serial_msgReset();
		Test_Serial_msgAppend(so_msg, 10, 0);
		LED_updateTickSendMsg(10);
//		Test_Serial_sendCmdAndData(cmd, (unsigned char *)msg, 9);
	}
#endif
}
void SOSZ_thread(enum e_mode _mode)
{
	SO_driver_timerUpdateDrivers(&szDriver[0], TOTAL_SZ, &SZ12to5_maskByte);

	SO_driver_timerUpdateDrivers(&soDriver[0], TOTAL_SO, &SO_mask);
	SO_driver_timerUpdatePhyDrivers(&soPhyDriver[0], TOTAL_SO, &SO_mask);

	SOSZ_serialDebugThread();

	SO_driver_timerUpdateDrivers(&rlDriver[0], MAX_REL, &REL_lo_mask);
	SO_driver_timerUpdatePhyDrivers(&rlPhyDriver[0], MAX_REL, &REL_lo_mask);
}
void SOSZ_notifySOSZ_SIwarAlm(BYTE index)
{
	SIWar_maskByte |= index;
}
void SOSZ_notifySOSZ_SZtrigger8(BYTE index);
void SOSZ_clearSOSZ_SZtrigger8(BYTE index);
void SOSZ_notifySOSZ_SZtrigger(WORD index)
{
	WORD temp = 0;
	BYTE sz4to1mask = 0;
	temp = (index&0x000F)>>0;
	sz4to1mask = temp&0x0F;

	BYTE sz12to5_mask = 0;
	temp = (index&0x0FF0)>>4;
	sz12to5_mask = temp&0xFF;

	WORD newIndex = sz12to5_mask;
	newIndex = newIndex<<4;
	newIndex += sz4to1mask;
	SZ_maskWord |= newIndex;

	if (sz4to1mask)
	{
//		SOSZ_notifySOSZ_SZtrigger8(sz4to1mask); // 1 to 4
		sz4to1mask = sz4to1mask<<4;
		SOSZ_notifySOSZ_SIHiAlm(sz4to1mask); // sz4to1_si12to9_maskByte
	}
	if (sz12to5_mask)
	{
//		SZ12to5_maskByte &= ~sz4to1mask;
		sz12to5_maskByte |= sz12to5_mask;
//		BYTE sz8to5mask = (sz12to5_mask&0x0F)<<4;
//		if (sz8to5mask)
			SOSZ_notifySOSZ_SZtrigger8(sz12to5_maskByte); // 5 to 8
	}
}
void SOSZ_clearSOSZ_SZtrigger(WORD index)
{
	WORD temp = 0;
	BYTE sz4to1mask = 0;
	temp = (index&0x000F)>>0;
	sz4to1mask = temp&0x0F;

	BYTE sz12to5_mask = 0;
	temp = (index&0x0FF0)>>4;
	sz12to5_mask = temp&0xFF;

	WORD newIndex = sz12to5_mask;
	newIndex = newIndex<<4;
	newIndex += sz4to1mask;
	SZ_maskWord &= ~newIndex;

	if (sz4to1mask)
	{
//		SOSZ_clearSOSZ_SZtrigger8(sz4to1mask); // 1 to 4
		sz4to1mask = sz4to1mask<<4;
		SOSZ_clearSOSZ_SIHiAlm(sz4to1mask); // sz4to1_si12to9_maskByte
	}
	if (sz12to5_mask)
	{
//		SZ12to5_maskByte &= ~sz4to1mask;
		sz12to5_maskByte &= ~sz12to5_mask;
//		BYTE sz8to5mask = (sz12to5_mask&0x0F)<<4;
//		if (sz8to5mask)
			SOSZ_clearSOSZ_SZtrigger8(sz12to5_maskByte); // 5 to 8
	}
}
void SOSZ_notifySOSZ_SZtrigger8(BYTE index)
{
	SZ12to5_maskByte |= index;
}
void SOSZ_clearSOSZ_SZtrigger8(BYTE index)
{
	SZ12to5_maskByte &= ~index;
}
void SOSZ_notifySOSZ_SZtrigger_test(WORD index)
{
	#ifdef TEST_OVERRIDES
	SOSZ_notifySOSZ_SZtrigger(index);
	#endif
}
void SOSZ_notifySOSZ_SZtrigger8_test(BYTE index)
{
	#ifdef TEST_OVERRIDES
	SOSZ_notifySOSZ_SZtrigger8(index);
	#endif
}
void SOSZ_notifySOSZ_SZtriggerHi_test(BYTE index)
{
	#ifdef TEST_OVERRIDES
	SOSZ_notifySOSZ_SZtrigger8(index);
	#endif
}
void SOSZ_clearSOSZ_SZtrigger_test(WORD index)
{
	#ifdef TEST_OVERRIDES
	SOSZ_clearSOSZ_SZtrigger(index);
	#endif
}
void SOSZ_clearSOSZ_SZtrigger8_test(BYTE index)
{
	#ifdef TEST_OVERRIDES
	SOSZ_clearSOSZ_SZtrigger8(index);
	#endif
}
void SOSZ_notifySOSZ_SIHiAlm(BYTE index)
{
	sz4to1_si12to9_maskByte |= index;
}
void SOSZ_notifySOSZ_SILoAlm(BYTE index)
{
	si8to1_maskByte |= index;
}
void SOSZ_notifySOSZ_SOtrigger(BYTE index)
{
	SO_mask |= index;
}
/*void SOSZ_notifySOSZ_SOtriggerFWS(BYTE index)
{
	SO_maskFWS |= index;
}*/
void SOSZ_updateSOSZ_SOnormalState(void)
{
	SO_normalState = 0;
	int i;
	struct SO * pSO;
	for(i=0;i<TOTAL_SO;i++) {
//		soDriver[i].pSOconfig = &configMemRAM.so[i];
		pSO = (struct SO *)&pConfigMemRAM->so[i];
		if (pSO->NormallyOn)
		{
			SO_normalState |= (1<<i);
		}
	}
}
BYTE SOSZ_getSOSZ_SOnormalState(void)
{
	return SO_normalState;
}
BYTE SOSZ_getSOSZ_SOtrigger(void)
{
	return SO_mask;
}
void SOSZ_notifySOSZ_RELtrigger(BYTE index)
{
	REL_lo_mask |= index;
}
/*void SOSZ_notifySOSZ_RELtriggerFWS(BYTE index)
{
	REL_lo_maskFWS |= index;
}*/
enum objectStatus SO_objStatus(enum objectType type, enum objectNumber num)
{
	enum objectStatus stat = OBJ_S_INVALID;
	uint8_t mask8 = 0;
//	uint16_t mask16 = 0;
	uint8_t status8 = 0;
//	uint16_t status16 = 0;
	uint8_t return8 = 0;
//	uint16_t return16 = 0;
//	uint8_t temp8 = 0;
//	uint16_t temp16 = 0;
	switch (type)
	{
		case OBJ_T_SO:
			if (/*num >= OBJ_1 &&*/ num <= OBJ_4)
			{
				stat = OBJ_S_INACTIVE;
				status8 = SOSZ_getSOSZ_SOtrigger();
				mask8 = (1<<num);
				return8 = mask8&status8;
			}
			break;
		case OBJ_T_SZ:
			if (/*num >= OBJ_1 &&*/ num <= OBJ_4)
			{
				stat = OBJ_S_INACTIVE;
				status8 = sz4to1_si12to9_maskByte;
				mask8 = (1<<num)<<4;
				return8 = mask8&status8;
			}
			else if (num >= OBJ_5 && num <= OBJ_12)
			{
				stat = OBJ_S_INACTIVE;
				status8 = sz12to5_maskByte;
				mask8 = (1<<(num-OBJ_5));
				return8 = mask8&status8;
			}
			break;
		case OBJ_T_RL:
			break;
		case OBJ_T_SI:
			if (/*num >= OBJ_1 &&*/ num <= OBJ_8)
			{
				stat = OBJ_S_INACTIVE;
				mask8 = (1<<(num - 0));
				status8 = SOSZ_getSOSZ_SILoAlmTrigger(); // si8to1_maskByte
				return8 = mask8&status8;
			}
			else if (num >= OBJ_9 && num <= OBJ_12)
			{
				stat = OBJ_S_INACTIVE;
				status8 = sz4to1_si12to9_maskByte;
				mask8 = (1<<(num-OBJ_9));
				return8 = mask8&status8;
			}
			break;
		case OBJ_T_NULL:
			break;
	}
	if (return8)
	{
		stat = OBJ_S_ACTIVE;
	}
	return stat;
}
unsigned char SOSZ_getSOSZ_SILoAlmTrigger(void)
{
	return si8to1_maskByte;
}
WORD SOSZ_getSOSZ_SZTrigger(void)
{
	return SZ_maskWord;
}
BYTE SOSZ_getSOSZ_SZLowTrigger(void)
{
	return SZ12to5_maskByte;
}
void SOSZ_clearSOSZ_SZLowTrigger(BYTE index)
{
	SZ12to5_maskByte &= ~index;
}
void SOSZ_clearSOSZ_SIwarAlm(BYTE index)
{
	SIWar_maskByte &= ~index;
}
void SOSZ_clearSOSZ_SIHiAlm(BYTE index)
{
	sz4to1_si12to9_maskByte &= ~index;
}
void SOSZ_clearSOSZ_SILoAlm(BYTE index)
{
	si8to1_maskByte &= ~index;
}
void SOSZ_clearSOSZ_SOtrigger(BYTE index)
{
	SO_mask &= ~index;
}
void SOSZ_clearSOSZ_RELtrigger(BYTE index)
{
	REL_lo_mask &= ~index;
}
/*void SOSZ_clearSOSZ_SOtriggerFWS(BYTE index)
{
	SO_maskFWS &= ~index;
}
void SOSZ_clearSOSZ_RELtriggerFWS(BYTE index)
{
	REL_lo_maskFWS &= ~index;
}*/
void SOSZ_test_setConfigA(struct SO *p, BYTE normOn, BYTE inhibit, BYTE outputCtl, BYTE abort)
{
	p->NormallyOn = normOn; // 1
	p->InhibitService = inhibit; // 1
	p->Unused1 = 0; // 1
	p->OutputControl = outputCtl; // 2
//	p->AbortInput = abort; // 3
	BYTE *t = (BYTE *)&p->Start;
	t++;
	*t |= (abort&0x07)<<5; // &0xE0
}
void SOSZ_test_setConfigB(struct SO *p, BYTE mask)
{	// MSB AbortInput, LSB NormallyOn
	BYTE * pc = (BYTE *)p;
	*(pc+1) = mask;
}
void SOSZ_test_setOps(struct SO *p, BYTE termMask)
{	// MSB bit7 unused, LSB bit0 Term1Op
	// 1 - or operation, 0 - and operation
	BYTE * pc = (BYTE *)p;
	*(pc+2) = termMask;
}
void SOSZ_test_setTermX(struct SO *p, BYTE term, BYTE siWar, BYTE sz, BYTE sz4to1_si12to9, BYTE si8to1)
{
	/* 							7 6 5 4 3 2 1 0
	 * siWar 			-- sw08 sw07 sw06 sw05 sw04 sw03 sw02 sw01
	 * sz				--	sz12 sz11 sz10 sz09 sz08 sz07 sz06 sz05
	 * sz4to1_si12to9	--	sz04 sz03 sz02 sz01 si12 si11 si10 si09
	 * si8to1 			--	si08 si07 si06 si05 si04 si03 si02 si01
	 */
	BYTE * pc = (BYTE *)p;
	BYTE offset = term*4 - 1;
	*(pc+offset+0) = siWar;
	*(pc+offset+1) = sz;
	*(pc+offset+2) = sz4to1_si12to9;
	*(pc+offset+3) = si8to1;
}
void SOSZ_test_setTimers(struct SO *p, BYTE turnOn, BYTE turnOff, BYTE per, BYTE on, BYTE off)
{
	p->timers.TurnOnDelay = turnOn; // 00001010
	p->timers.TurnOffDelay = turnOff; // 00001100
	p->timers.PulsePeriod = per; // 00000000
	p->timers.PulseOnTimer = on; // 00000000
	p->timers.PulseOffTimer = off; // 00000000
}

void SOSZ_clearAllMasks()
{
	SOSZ_clearSOSZ_SOtrigger(0xFF);
	SOSZ_clearSOSZ_SZtrigger(0xFFF);
	SOSZ_clearSOSZ_SZLowTrigger(0xFF);
	SOSZ_clearSOSZ_RELtrigger(0xFF);
	SOSZ_clearSOSZ_SIwarAlm(0xFF);
	SOSZ_clearSOSZ_SIHiAlm(0xFF);
	SOSZ_clearSOSZ_SILoAlm(0xFF);
}
void SOSZ_test_setup(void)
{
//	struct SO_state * pSOstate = &soDriver[0].SOstate;
//	memset((BYTE*)pSOstate, 0, sizeof(struct SO_state));
//	SOSZ_resetSOSZconfig(soDriver[0].pSOconfig, TOTAL_SO);
	SOSZ_resetSOSZdriver(&soDriver[0], TOTAL_SO);
	SOSZ_resetSOSZdriver(&szDriver[0], TOTAL_SZ);
	SOSZ_resetSOSZdriver(&rlDriver[0], MAX_REL);
	SOSZ_clearAllMasks();
}
void SOSZ_test_setupDriver(const struct SO_driver * _pSOd, BYTE index, BYTE numObjects)
{
	struct SO_driver * pSOd = (struct SO_driver *) _pSOd;
	struct SO_state * pSOstate = (struct SO_state *)&pSOd[index].SOstate;
	memset((BYTE*)pSOstate, 1, sizeof(struct SO_state));
	memset((BYTE*)pSOstate, 0, sizeof(struct SO_state));
//	SOSZ_resetSOSZconfig(pSOd[index].pSOconfig numObjects);
	SOSZ_resetSOSZdriver(pSOd, numObjects);
	SOSZ_clearAllMasks();
}
void SOSZ_test_allMasksSetup(void)
{
	SOSZ_notifySOSZ_SIHiAlm(0xFF);
	SOSZ_notifySOSZ_SILoAlm(0xFF);
	SOSZ_notifySOSZ_SZtrigger(0xFF);
	SOSZ_notifySOSZ_SIwarAlm(0xFF);
//	SOSZ_notifySOSZ_SOtrigger(0xFF);
}
void SOSZ_test_noMasks_setup(void)
{
	SOSZ_clearAllMasks();
	SOSZ_notifySOSZ_SIHiAlm(0);
	SOSZ_notifySOSZ_SILoAlm(0);
	SOSZ_notifySOSZ_SZtrigger(0);
	SOSZ_notifySOSZ_SIwarAlm(0);
//	SOSZ_notifySOSZ_SOtrigger(0);
}
void SOSZ_test_triggerSetupOneForAll(BYTE mask)
{
	struct SO * pSO;
	int i, term;
	for(i=0; i<TOTAL_SO; i++)
	{
		pSO = soDriver[i].pSOconfig;
		SOSZ_test_setOps(pSO, 0);
		for (term=TERM1; term<=TERM4; term++)
			SOSZ_test_setTermX(pSO, term, mask, mask, mask, mask);
	}
}
void SOSZ_test_noTriggersAllMasks(void)
{
	SOSZ_test_setup();
	SOSZ_test_triggerSetupOneForAll(0);
	SOSZ_test_allMasksSetup();
	SOSZ_thread(MODE_NORMAL);
}
void SOSZ_test_noTriggersNoMasks(void)
{
	SOSZ_test_setup();
	SOSZ_test_triggerSetupOneForAll(0);
	SOSZ_test_noMasks_setup();
	SOSZ_thread(MODE_NORMAL);
}
void SOSZ_test_oneTriggerEachAllMasks(void)
{
	SOSZ_test_setup();
	SOSZ_test_triggerSetupOneForAll(1);
	SOSZ_test_allMasksSetup();
	SOSZ_thread(MODE_NORMAL);
}
void SOSZ_test_opTest(BYTE mask)
{ // MSB unused, LSB Term1Op
	struct SO * pSO = soDriver[0].pSOconfig;
	SOSZ_test_setup();
	SOSZ_test_triggerSetupOneForAll(1);
	SOSZ_test_allMasksSetup();
	SOSZ_test_setOps(pSO, mask);
	SOSZ_thread(MODE_NORMAL);
}
void SOSZ_test_oneTriggerEachNoMasks(void)
{
	SOSZ_test_setup();
	SOSZ_test_triggerSetupOneForAll(1);
	SOSZ_test_noMasks_setup();
	SOSZ_thread(MODE_NORMAL);
}
void SOSZ_test_oneTriggerOneMask(void)
{
	SOSZ_test_setup();
	SOSZ_test_setTermX(soDriver[0].pSOconfig, TERM1, 0, 0, 0, 1<<5);
	SOSZ_notifySOSZ_SILoAlm(1<<5);
	SOSZ_thread(MODE_NORMAL);
}
enum phyType {
	isRelay = 0,
	isSO = 1,
	isSZ = 2
};
void SOSZ_test_demoConfig_helper(BYTE soMe, BYTE type, BYTE term)
{
	struct SO * pSO;
	if (type == isSO)
	{
		pSO = soDriver[soMe].pSOconfig;
	}
	else if (type == isRelay)
	{
		pSO = rlDriver[soMe].pSOconfig;
	}
	else if (type == isSZ)
	{
		pSO = szDriver[soMe].pSOconfig;
	}
//  void SOSZ_test_setConfigA(struct SO *p, BYTE normOn, BYTE inhibit, BYTE outputCtl, BYTE abort)
	SOSZ_test_setConfigA(pSO, 0, 0, SO_configByte_OutputControl_andOr, 0);
//  void SOSZ_test_setOps(struct SO *p, BYTE termMask)
	SOSZ_test_setOps(pSO, 0xFF); // MSB unused, LSB Term1Op, 1=or, 0=and
//  void SOSZ_test_setTermX(struct SO *p, BYTE term, BYTE siWar, BYTE sz, BYTE siHi, BYTE siLo)
	/* 			7 6 5 4 3 2 1 0
	 * siWar -- sw08 sw07 sw06 sw05 sw04 sw03 sw02 sw01
	 * sz	--	sz12 sz11 sz10 sz09 sz08 sz07 sz06 sz05
	 * siHi	--	sz04 sz03 sz02 sz01 si12 si11 si10 si09
	 * siLo --	si08 si07 si06 si05 si04 si03 si02 si01
	 */
	SOSZ_test_setTermX(pSO, TERM1, 0, 0, 0, term);
	SOSZ_test_setTermX(pSO, TERM2, 0, 0, 0, 0);//0x02);
	SOSZ_test_setTermX(pSO, TERM3, 0, 0, 0, 0);
	SOSZ_test_setTermX(pSO, TERM4, 0, 0, 0, 0);
//  void SOSZ_test_setTimers(struct SO *p, BYTE turnOn, BYTE turnOff, BYTE per, BYTE on, BYTE off)
	SOSZ_test_setTimers(pSO, 0, 0, 0, 0, 0);
}
enum SO_INPUT_TYPE {
	SO_INPUT_SIWAR8to0 = 1,
	SO_INPUT_TERM_ORDER_SZHi_SZ12to5 = 2,
	SO_INPUT_TERM_ORDER_SIHI_SZ4to1_SI12to9 = 3,
	SO_INPUT_TERM_ORDER_SILO_SI8to1 = 4
};
enum SO_INPUT_MASK {
	SO_INPUT_SIWAR08 = 0x80,
	SO_INPUT_SIWAR07 = 0x40,
	SO_INPUT_SIWAR06 = 0x20,
	SO_INPUT_SIWAR05 = 0x10,
	SO_INPUT_SIWAR04 = 0x08,
	SO_INPUT_SIWAR03 = 0x04,
	SO_INPUT_SIWAR02 = 0x02,
	SO_INPUT_SIWAR01 = 0x01,
	SO_INPUT_SZ12 = 0x80,
	SO_INPUT_SZ11 = 0x40,
	SO_INPUT_SZ10 = 0x20,
	SO_INPUT_SZ09 = 0x10,
	SO_INPUT_SZ08 = 0x08,
	SO_INPUT_SZ07 = 0x04,
	SO_INPUT_SZ06 = 0x02,
	SO_INPUT_SZ05 = 0x01,
	SO_INPUT_SZ04 = 0x80,
	SO_INPUT_SZ03 = 0x40,
	SO_INPUT_SZ02 = 0x20,
	SO_INPUT_SZ01 = 0x10,
	SO_INPUT_SI12 = 0x08,
	SO_INPUT_SI11 = 0x04,
	SO_INPUT_SI10 = 0x02,
	SO_INPUT_SI09 = 0x01,
	SO_INPUT_SI08 = 0x80,
	SO_INPUT_SI07 = 0x40,
	SO_INPUT_SI06 = 0x20,
	SO_INPUT_SI05 = 0x10,
	SO_INPUT_SI04 = 0x08,
	SO_INPUT_SI03 = 0x04,
	SO_INPUT_SI02 = 0x02,
	SO_INPUT_SI01 = 0x01
};
void SOSZ_testSetSOinput(BYTE soMe, BYTE type, enum SO_INPUT_TYPE soInputType, enum SO_INPUT_MASK mask)
{
	struct SO * pSO;
	if (type == isSO)
	{
		pSO = soDriver[soMe].pSOconfig;
	}
	else if (type == isRelay)
	{
		pSO = rlDriver[soMe].pSOconfig;
	}
	else if (type == isSZ)
	{
		pSO = szDriver[soMe].pSOconfig;
	}
	//  void SOSZ_test_setTermX(struct SO *p, BYTE term, BYTE siWar, BYTE sz, BYTE siHi, BYTE siLo)
	/* 			7 6 5 4 3 2 1 0
	 * siWar -- sw08 sw07 sw06 sw05 sw04 sw03 sw02 sw01
	 * sz	--	sz12 sz11 sz10 sz09 sz08 sz07 sz06 sz05
	 * siHi	--	sz04 sz03 sz02 sz01 si12 si11 si10 si09
	 * siLo --	si08 si07 si06 si05 si04 si03 si02 si01
	 */
	switch (soInputType)
	{
		case SO_INPUT_SIWAR8to0:
			SOSZ_test_setTermX(pSO, TERM1, mask, 0, 0, 0);
			break;
		case SO_INPUT_TERM_ORDER_SZHi_SZ12to5:
			SOSZ_test_setTermX(pSO, TERM1, 0, mask, 0, 0);
			break;
		case SO_INPUT_TERM_ORDER_SIHI_SZ4to1_SI12to9:
			SOSZ_test_setTermX(pSO, TERM1, 0, 0, mask, 0);
			break;
		case SO_INPUT_TERM_ORDER_SILO_SI8to1:
			SOSZ_test_setTermX(pSO, TERM1, 0, 0, 0, mask);
			break;
	}

	SOSZ_test_setConfigA(pSO, 0, 0, SO_configByte_OutputControl_andOr, 0);
//  void SOSZ_test_setOps(struct SO *p, BYTE termMask)
	SOSZ_test_setOps(pSO, 0xFF); // MSB unused, LSB Term1Op, 1=or, 0=and
	SOSZ_test_setTimers(pSO, 0, 0, 0, 0, 0);
}

void SOSZ_test_stdTest(void)
{
//	SOSZ_test_setup();

/*	pSO = szDriver[0].pSOconfig;
	//void SOSZ_test_setConfigA(struct SO *p, BYTE normOn, BYTE inhibit, BYTE outputCtl, BYTE abort)
	SOSZ_test_setConfigA(pSO, 0, 0, 1, 0);
	SOSZ_test_setOps(pSO, 0xF0); // MSB unused, LSB Term1Op, 1=or, 0=and
//  void SOSZ_test_setTermX(struct SO *p, BYTE term, BYTE siWar, BYTE sz, BYTE siHi, BYTE siLo)
	SOSZ_test_setTermX(pSO, TERM1, 0, 0, 0, 0x01);
	SOSZ_test_setTermX(pSO, TERM2, 0, 0, 0, 0);
	SOSZ_test_setTermX(pSO, TERM3, 0, 0, 0, 0);
	SOSZ_test_setTermX(pSO, TERM4, 0, 0, 0, 0);
	//void SOSZ_test_setTimers(struct SO *p, BYTE turnOn, BYTE turnOff, BYTE per, BYTE on, BYTE off)
	SOSZ_test_setTimers(pSO, 0, 0, 0, 0, 30);*/

	SOSZ_test_demoConfig_helper(0, isSO, 0x01);
	SOSZ_test_demoConfig_helper(1, isSO, 0x02);
	SOSZ_test_demoConfig_helper(2, isSO, 0x04);
	SOSZ_test_demoConfig_helper(3, isSO, 0x08);
	SOSZ_test_demoConfig_helper(0, isRelay, 0x10);
	SOSZ_test_demoConfig_helper(1, isRelay, 0x20);
	SOSZ_test_demoConfig_helper(2, isRelay, 0x40);
	SOSZ_test_demoConfig_helper(3, isRelay, 0x80);


	struct SO * pSO;
	pSO = szDriver[0].pSOconfig;
	SOSZ_test_demoConfig_helper(0, isSZ, 0x01);

//	void SOSZ_test_setTimers(struct SO *p, BYTE turnOn, BYTE turnOff, BYTE per, BYTE on, BYTE off)
	SOSZ_test_setTimers(pSO, 2, 0, 0, 0, 0);

	pSO = soDriver[0].pSOconfig;
	SOSZ_test_setTimers(pSO, 0, 2, 0, 0, 0);


	pSO = soDriver[1].pSOconfig;
//  void SOSZ_test_setTermX(struct SO *p, BYTE term, BYTE siWar, BYTE sz, BYTE siHi, BYTE siLo)
//	SOSZ_test_setTermX(pSO, TERM1, 0, 0x01, 0, 0);
	SOSZ_test_setTimers(pSO, 0, 2, 0, 0, 0);


#if 0
	struct SO * pSO;

	pSO = soDriver[0].pSOconfig;
	SOSZ_test_setConfigA(pSO, 0, 0, 1, 0);
	SOSZ_test_setOps(pSO, 0xF0); // MSB unused, LSB Term1Op, 1=or, 0=and
//  void SOSZ_test_setTermX(struct SO *p, BYTE term, BYTE siWar, BYTE sz, BYTE siHi, BYTE siLo)
	SOSZ_test_setTermX(pSO, TERM1, 0, 0, 0, 0x01);
	SOSZ_test_setTermX(pSO, TERM2, 0, 0, 0, 0);//0x02);
	SOSZ_test_setTermX(pSO, TERM3, 0, 0, 0, 0);
	SOSZ_test_setTermX(pSO, TERM4, 0, 0, 0, 0);
	SOSZ_test_setTimers(pSO, 0, 1, 0, 0, 0);

	pSO = soDriver[1].pSOconfig;
	// Config = 00001000
	SOSZ_test_setConfigA(pSO, 0, 0, 1, 0);
	SOSZ_test_setOps(pSO, 0x00); // MSB unused, LSB Term1Op, 1=or, 0=and
	// Trigger Config = 11110000, 1 is or, 0 is and
	SOSZ_test_setTermX(pSO, TERM1, 0, 0, 0, 0x01);
	SOSZ_test_setTermX(pSO, TERM2, 0, 0, 0, 0x02);
	SOSZ_test_setTermX(pSO, TERM3, 0, 0, 0, 0);
	SOSZ_test_setTermX(pSO, TERM4, 0, 0, 0, 0);
	SOSZ_test_setTimers(pSO, 0x05, 0x0C, 10, 3, 3);

	pSO = soDriver[2].pSOconfig;
	// Config = 00001000
	SOSZ_test_setConfigA(pSO, 0, 0, 1, 0);
	SOSZ_test_setOps(pSO, 0x00); // MSB unused, LSB Term1Op, 1=or, 0=and
	// Trigger Config = 11110000, 1 is or, 0 is and
	SOSZ_test_setTermX(pSO, TERM1, 0, 0, 0, 0x01);
	SOSZ_test_setTermX(pSO, TERM2, 0, 0, 0, 0);
	SOSZ_test_setTermX(pSO, TERM3, 0, 0, 0, 0);
	SOSZ_test_setTermX(pSO, TERM4, 0, 0, 0, 0);
	SOSZ_test_setTimers(pSO, 0, 0, 0, 0, 0);

	pSO = soDriver[3].pSOconfig;
	// Config = 00001000
	SOSZ_test_setConfigA(pSO, 0, 0, 1, 0);
	SOSZ_test_setOps(pSO, 0x00); // MSB unused, LSB Term1Op, 1=or, 0=and
	// Trigger Config = 11110000, 1 is or, 0 is and
	SOSZ_test_setTermX(pSO, TERM1, 0, 0, 0, 0x01);
	SOSZ_test_setTermX(pSO, TERM2, 0, 0, 0, 0);
	SOSZ_test_setTermX(pSO, TERM3, 0, 0, 0, 0);
	SOSZ_test_setTermX(pSO, TERM4, 0, 0, 0, 0);
	SOSZ_test_setTimers(pSO, 0, 1, 0, 0, 0);

#endif
//	SO_initStates();
}
struct SO * SOSZ_testGetSoPtr(BYTE soMe, enum SO_objectType type)
{
	struct SO * pSO;
	if (type == SO_T_SO)
	{
		pSO = soDriver[soMe].pSOconfig;
	}
	else if (type == SO_T_RL)
	{
		pSO = rlDriver[soMe].pSOconfig;
	}
	else if (type == SO_T_SZ)
	{
		pSO = szDriver[soMe].pSOconfig;
	}
	return pSO;
}
RTN_TYPE SO_isCfgValid(enum SO_objectType type, enum SO_objectNumber objNum)
{
	RTN_TYPE rtn = RTN_ERR_OBJECT_DOES_NOT_EXIST;
	struct SO *pSO;
	struct SO_driver *pSOd;
	switch(type)
	{
		case SO_T_SO:
			pSOd = &soDriver[objNum];
			break;
		case SO_T_SZ:
			pSOd = &szDriver[objNum];
			break;
		case SO_T_RL:
			pSOd = &rlDriver[objNum];
			break;
	}
	if (pSOd==0)
		return RTN_ERR_OBJECT_DOES_NOT_EXIST;
	pSO = pSOd->pSOconfig;
	if (pSO==0)
		return RTN_ERR_OBJECT_DOES_NOT_EXIST;
	rtn = RTN_ERR_CFG_INVALID;
	if (pSO->OutputControl == SO_configByte_OutputControl_disabled)
	{
		pSOd->SOstate.h1State = INHIBITED;
		return rtn;
	}
	int i;
	int termCount=0;
	for (i=0; i<4; i++)
	{
		termCount += pSO->term[i].SIHiTriggers;
		termCount += pSO->term[i].SILoTriggers;
		termCount += pSO->term[i].SIWarTriggers;
		termCount += pSO->term[i].SZTriggers;
	}
	if (termCount)
	{
		pSOd->SOstate.h1State = ENABLED;
		rtn = RTN_CFG_VALID;
	}
	return rtn;

}
void SO_FWS_setSoMode(enum SO_objectType type, enum SO_objectNumber objNum, enum SO_mode mode)
{
//	struct SO_outputPhyDriver *pSOdPhy = 0;
	struct SO_driver *pSOd;
	if (type == SO_T_SO)
	{
//		pSOdPhy = &soPhyDriver[objNum];
		pSOd = &soDriver[objNum];
	}
	else if (type == SO_T_RL)
	{
//		pSOdPhy = &rlPhyDriver[objNum];
		pSOd = &rlDriver[objNum];
	}
	if (pSOd != 0)
	{
//		pSOdPhy->mode = mode;
//		pSOdPhy->pSosz->SOstate.mode = mode;
		pSOd->SOstate.mode = mode;
/*		if (mode == SO_MODE_SO)
		{
			struct SO *pSO = pSOd->pSOconfig;
			SOSZ_resetSOSZconfig(pSO, 1);
		}*/
	}
}
void SOSZ_test_GAfxnSO(BYTE soMe, enum SO_objectType type)
{
	struct SO * pSO = SOSZ_testGetSoPtr(soMe, type);

//  void SOSZ_test_setConfigA(struct SO *p, BYTE normOn, BYTE inhibit, BYTE outputCtl, BYTE abort)
	SOSZ_test_setConfigA(pSO, 0, 0, SO_configByte_OutputControl_genAlarm, 0);

	if (pSO->OutputControl&SO_configByte_OutputControl_genAlarm == SO_configByte_OutputControl_genAlarm)
	{
		__no_operation();
	}
	//  void SOSZ_test_setOps(struct SO *p, BYTE termMask)
	SOSZ_test_setOps(pSO, 0xFF); // MSB unused, LSB Term1Op, 1=or, 0=and

	//  void SOSZ_test_setTermX(struct SO *p, BYTE term, BYTE siWar, BYTE sz, BYTE siHi, BYTE siLo)
	/* 			7 6 5 4 3 2 1 0
	 * siWar -- sw08 sw07 sw06 sw05 sw04 sw03 sw02 sw01
	 * sz	--	sz12 sz11 sz10 sz09 sz08 sz07 sz06 sz05
	 * siHi	--	sz04 sz03 sz02 sz01 si12 si11 si10 si09
	 * siLo --	si08 si07 si06 si05 si04 si03 si02 si01
	 */
	SOSZ_test_setTermX(pSO, TERM1, 0, 0, 0, 0);
	SOSZ_test_setTermX(pSO, TERM2, 0, 0, 0, 0);//0x02);
	SOSZ_test_setTermX(pSO, TERM3, 0, 0, 0, 0);
	SOSZ_test_setTermX(pSO, TERM4, 0, 0, 0, 0);
//  void SOSZ_test_setTimers(struct SO *p, BYTE turnOn, BYTE turnOff, BYTE per, BYTE on, BYTE off)
	SOSZ_test_setTimers(pSO, 0, 0, 0, 0, 0);
}

void SOSZ_test_franceConfig5(void)
{
	SOSZ_test_demoConfig_helper(0, isSO, 0x01);
	SOSZ_test_demoConfig_helper(1, isSO, 0x02);
	SOSZ_test_demoConfig_helper(2, isSO, 0x04);
	SOSZ_test_demoConfig_helper(3, isSO, 0x08);
	SOSZ_test_demoConfig_helper(0, isRelay, 0x10);
	SOSZ_test_demoConfig_helper(1, isRelay, 0x20);
	SOSZ_test_demoConfig_helper(2, isRelay, 0x40);
	SOSZ_test_demoConfig_helper(3, isRelay, 0x80);

	struct SO * pSO;
	pSO = szDriver[0].pSOconfig;
	SOSZ_test_demoConfig_helper(0, isSZ, 0x01);
//	void SOSZ_test_setTimers(struct SO *p, BYTE turnOn, BYTE turnOff, BYTE per, BYTE on, BYTE off)
	SOSZ_test_setTimers(pSO, 20, 0, 0, 0, 0);

	pSO = soDriver[0].pSOconfig;
	SOSZ_test_setTermX(pSO, TERM1, 0, 0, 0, 0);
	//	void SOSZ_testSetSOinput(BYTE soMe, BYTE type, enum SO_INPUT_TYPE soInputType, enum SO_INPUT_MASK mask)
	SOSZ_testSetSOinput(0, isSO, SO_INPUT_TERM_ORDER_SIHI_SZ4to1_SI12to9, SO_INPUT_SZ01);
	SOSZ_test_setTimers(pSO, 0, 2, 0, 0, 0);

	pSO = soDriver[1].pSOconfig;
//  void SOSZ_test_setTermX(struct SO *p, BYTE term, BYTE siWar, BYTE sz, BYTE siHi, BYTE siLo)
//	SOSZ_test_setTermX(pSO, TERM1, 0, 0x01, 0, 0);
	SOSZ_test_setTimers(pSO, 0, 2, 0, 0, 0);

}

void SOSZ_test_demoConfig_setup(void)
{
	SOSZ_test_stdTest();
//	SOSZ_test_franceConfig5();
}
void SOSZ_test_bistableConfig_setup(void)
{
	SOSZ_test_setup();
	struct SO * pSO;
	struct SO * pSZ;
	pSO = soDriver[0].pSOconfig;
	pSZ = szDriver[0].pSOconfig;
	// Config = 00001000
	SOSZ_test_setConfigA(pSO, 0, 0, SO_configByte_OutputControl_andOr, 0);

//	SOSZ_test_setOps(pSO, 0xF0); // MSB unused, LSB Term1Op
	// Trigger Config = 11110000, 1 is or, 0 is and

	void SOSZ_test_setTermX(struct SO *p, BYTE term, BYTE siWar, BYTE sz, BYTE siHi, BYTE siLo);
	SOSZ_test_setOps(pSO, 0xF0);
	SOSZ_test_setTermX(pSO, TERM1, 0, 0x01, 0, 0x00);
//	SOSZ_test_setTimers(pSO, 0x05, 0x0C, 10, 3, 3);
	pSO++;
	SOSZ_test_setOps(pSO, 0xF0);
	SOSZ_test_setTermX(pSO, TERM1, 0, 0x02, 0, 0x00);
//	SOSZ_test_setTimers(pSO, 0x05, 0x0C, 10, 3, 3);

	SOSZ_test_setOps(pSZ, 0xF0);
	SOSZ_test_setTermX(pSZ, TERM1, 0, 0x02, 0, 0x01);
//	SOSZ_test_setTimers(pSZ, 0x05, 0x0C, 10, 3, 3);
	pSZ++;
	SOSZ_test_setOps(pSZ, 0xF0);
	SOSZ_test_setTermX(pSZ, TERM1, 0, 0x01, 0, 0x02);
//	SOSZ_test_setTimers(pSZ, 0x05, 0x0C, 10, 3, 3);

//	SO_initStates();
}
void SOSZ_test_bistableConfig_test1(void)
{
	struct SO_driver * pSOd = &soDriver[0];
//	struct SO * pSO = pSOd->pSOconfig;
//	struct SO_timers * pTimer = &pSOd->timers;
	struct SO_state * pSOstate = &pSOd->SOstate;

	SOSZ_notifySOSZ_SILoAlm(1<<0);
	SOSZ_notifySOSZ_SILoAlm(1<<1);

	volatile unsigned int i=0;//, len = pSO->timers.TurnOnDelay;

	i=0;
	while (!pSOstate->trigger) // on exit, i = 1
	{
		SOSZ_thread(MODE_NORMAL);
		i++;
		if (i==1000) break;
	}
}
void SOSZ_test_demoConfig_test1(void)
{
	struct SO_driver * pSOd = &soDriver[1];
//	struct SO * pSO = pSOd->pSOconfig;
//	struct SO_timers * pTimer = &pSOd->timers;
	struct SO_state * pSOstate = &pSOd->SOstate;

	SOSZ_notifySOSZ_SILoAlm(1<<0);
	SOSZ_notifySOSZ_SILoAlm(1<<1);

	volatile unsigned int i=0;//, len = pSO->timers.TurnOnDelay;

	i=0;
	while (!pSOstate->trigger) // on exit, i = 1
	{
		SOSZ_thread(MODE_NORMAL);
		i++;
	}
	i=0;
	while (!pSOstate->onEntry)
//	while (pTimer->TurnOnDelay) // on exit, i = 5
	{
		SOSZ_thread(MODE_NORMAL);
		i++;
	}
	i=0;
	while (!pSOstate->onEntry) // on exit, i = 1
	{
		SOSZ_thread(MODE_NORMAL);
		i++;
	}
	while (pSOstate->activeState != STEADY_ON)
	{
		SOSZ_thread(MODE_NORMAL);
		i++;
	}
	SOSZ_clearSOSZ_SILoAlm(0x3);
	i=0;
	while(pSOstate->trigger) // on exit, i = 1
	{
		SOSZ_thread(MODE_NORMAL);
		i++;
	}
	i=0;
	while(pSOstate->triggerTimerLatched) // on exit, i = 12
	{
		SOSZ_thread(MODE_NORMAL);
		i++;
	}
}
void SOSZ_test_init(void)
{
	struct SO_state * pSOstate = &soDriver[0].SOstate;
	memset((BYTE*)pSOstate, 1, sizeof(struct SO_state));
	memset((BYTE*)pSOstate, 0, sizeof(struct SO_state));

	SOSZ_test_setupDriver(&soDriver[0], 0, TOTAL_SO);
	SOSZ_test_demoConfig_setup();

#if 0
	SOSZ_test_noTriggersAllMasks();
//	SOSZ_test_noTriggersAllMasks();
	SOSZ_test_oneTriggerEachAllMasks();
	SOSZ_test_oneTriggerEachNoMasks();
	SOSZ_test_oneTriggerOneMask();

	SOSZ_test_opTest(0x55); // MSB unused, LSB Term1Op
	SOSZ_test_opTest(0xAA); // MSB unused, LSB Term1Op

	SOSZ_test_demoConfig_setup();
	SOSZ_test_demoConfig_test1();

	SOSZ_test_bistableConfig_setup();
	SOSZ_test_bistableConfig_test1();
#endif
}
